#include "stdafx.h"
#include "CValue.h"

#include "IPALDebuggingServices.h"
#include "IScriptObject.h"

#include "CDependencyObject.h"
#include "Xcp_IDependencyObject.h"

#include "CXMLObject.h"


CValue::CValue( const CValue & other )
{
	*this = other;
}

CValue::CValue( XINT32 val )
{
	this->m_count = 0;
	this->m_type = ValueType::valueAny;
	this->m_type = ValueType::valueSigned;
	this->m_fNeedsFreeValuePointer = FALSE;
	this->m_isIndependent = FALSE;
	this->m_iValue = val;

}

CValue::CValue()
{
	this->m_count = 0;
	this->m_type = ValueType::valueAny;
	this->m_fNeedsFreeValuePointer = FALSE;
	this->m_isIndependent = FALSE;
	this->m_iValue = 0;
}

void CValue_FreeValuePointer(CValue *pValue)
{
	pValue->FreeValuePointer();
}

CValue::~CValue()
{
	if(this->m_fNeedsFreeValuePointer)
		CValue_FreeValuePointer(this);
}

CValue & CValue::operator=( const CValue & other )
{
	this->m_count = other.m_count;
	this->m_type = other.m_type;
	this->m_fNeedsFreeValuePointer = FALSE;
	this->m_isIndependent = other.m_isIndependent;
	this->m_pvValue = other.m_pvValue;
	return *this;
}

bool CValue::operator==( const CValue & other )
{
	bool ret;


	if ( this->m_type == other.m_type )
	{
		switch ( this->m_type )
		{
		case valueFloat:
			ret = this->m_eValue ==other.m_eValue;
		case valueSigned:
			ret = this->m_iValue == other.m_iValue;
			break;
		case valueBool:
			ret = this->m_nValue == other.m_nValue;
			break;
		case valueEnum:
			ret = this->m_nValue == other.m_nValue;
			break;
		case valueColor:
			ret = this->m_nValue == other.m_nValue;
			break;
		case valueObject:
		case valueScriptObject:
		case valueXMLObject:
		case valueIObject:
		case valueIUnknown:
			ret = this->m_pvValue == other.m_pvValue;
			break;
		case valueString:
			ret = this->AsString().Equals(&other.AsString(),xstrCompareCaseInsensitive) == 0;
			break;
		case valueFloatArray:
		case valuePointArray:
			ret = this->m_count == other.m_count && this->m_peValue == other.m_peValue;
			break;
		case valueByteArray:
			ret = this->m_count== other.m_count && this->m_peByteValue == other.m_peByteValue;
			break;
		case valuePoint:
		case valueSize:
			ret = static_cast<struct XSIZEF *>(other.m_pvValue)->width == static_cast<struct XSIZEF *>(this->m_pvValue)->width &&
				static_cast<struct XSIZEF *>(other.m_pvValue)->height == static_cast<struct XSIZEF *>(this->m_pvValue)->height;
			break;
		case valueDouble:
			ret = *other.m_pdfValue == *this->m_pdfValue;

			break;
		case valueDPoint:
			ret = static_cast<struct XPOINTD *>(other.m_pvValue)->x == static_cast<struct XPOINTD *>(this->m_pvValue)->x &&
				static_cast<struct XPOINTD *>(other.m_pvValue)->y == static_cast<struct XPOINTD *>(this->m_pvValue)->y;
			break;
		case valueRect:
		case valueThickness:
		case valueCornerRadius:
			ret = static_cast<struct XRECTF_RB *>(other.m_pvValue)->left == static_cast<struct XRECTF_RB *>(this->m_pvValue)->left &&
				static_cast<struct XRECTF_RB *>(other.m_pvValue)->top == static_cast<struct XRECTF_RB *>(this->m_pvValue)->top &&
				static_cast<struct XRECTF_RB *>(other.m_pvValue)->right == static_cast<struct XRECTF_RB *>(this->m_pvValue)->right &&
				static_cast<struct XRECTF_RB *>(other.m_pvValue)->bottom == static_cast<struct XRECTF_RB *>(this->m_pvValue)->bottom;
			break;
		case valueInternalHandler:
			ret = this->m_pvValue == other.m_pvValue;
			break;
		case valueGridLength:
			ret = static_cast<struct XGRIDLENGTH *>(other.m_pvValue)->type == static_cast<struct XGRIDLENGTH *>(this->m_pvValue)->type &&
				static_cast<struct XGRIDLENGTH *>(other.m_pvValue)->value == static_cast<struct XGRIDLENGTH *>(this->m_pvValue)->value;
			break;
		case valueIntPtr:
			ret = static_cast<union XINT64_LARGE_INTEGER *>(other.m_pvValue)->LowPart == static_cast<union XINT64_LARGE_INTEGER *>(this->m_pvValue)->LowPart &&
				static_cast<union XINT64_LARGE_INTEGER *>(other.m_pvValue)->HighPart == static_cast<union XINT64_LARGE_INTEGER *>(this->m_pvValue)->HighPart;
			break;
		default:
			ret = false;
			break;
		}
	}
	else
	{
		ret = false;
	}
	return ret;
}

bool CValue::operator!=( const CValue & other )
{
	return !(*this == other);
}

void CValue::SetFloat( XFLOAT val )
{
	this->m_type = ValueType::valueFloat;
	this->m_count = 0;
	this->m_eValue = val;
	XASSERT(!m_fNeedsFreeValuePointer);

}

void CValue::SetSigned( XINT32 val )
{
	this->m_type = valueSigned;
	this->m_count = 0;
	this->m_iValue = val;
	XASSERT(!m_fNeedsFreeValuePointer);
}

void CValue::SetBool( XBOOL val )
{
	this->m_type = valueBool;
	this->m_count = 0;
	this->m_nValue = val!=0;
	XASSERT(!m_fNeedsFreeValuePointer);
}

void CValue::SetEnum( XUINT32 val )
{
	this->m_type = valueEnum;
	this->m_count = 0;
	this->m_nValue = val;
	XASSERT(!m_fNeedsFreeValuePointer);
}

void CValue::SetColor( XUINT32 val )
{
	this->m_type = valueColor;
	this->m_nValue = val;
	this->m_count = 0;
	XASSERT(!m_fNeedsFreeValuePointer);
}

void CValue::SetPoint( struct XPOINTF * val )
{

	this->m_type = valuePoint;

	//this->_bf0 = this->_bf0 & 0xFF000000 | 2;
	this->m_count = sizeof(XPOINTF) /sizeof(float);

	this->m_pvValue = val;
	XASSERT(!m_fNeedsFreeValuePointer);
}

void CValue::SetDouble( XDOUBLE * val )
{
	this->m_type = valueDouble;

	//this->_bf0 = this->_bf0 & 0xFF000000 | 1;
	this->m_count = 1;

	this->m_pdfValue = val;
	XASSERT(!m_fNeedsFreeValuePointer);
}

void CValue::SetDPoint( struct XPOINTD * val )
{
	this->m_type = valueDPoint;

	//this->_bf0 = this->_bf0 & 0xFF000000 | 2;
	this->m_count = sizeof(XPOINTD) /sizeof(XDOUBLE);
	this->m_pvValue = val;
	XASSERT(!m_fNeedsFreeValuePointer);
}

void CValue::SetRect( struct XRECTF_WH * val )
{
	this->m_type = valueRect;

	//this->_bf0 = this->_bf0 & 0xFF000000 | 4;
	this->m_count = sizeof(XRECTF_WH) /sizeof(XFLOAT);

	this->m_pvValue = val;
	XASSERT(!m_fNeedsFreeValuePointer);
}

void CValue::SetObject( struct XCP_IDependencyObject * val )
{
	this->m_type = valueObject;
	this->m_count = 0;
	this->m_pvValue = val;
	XASSERT(!m_fNeedsFreeValuePointer);
}

void CValue::SetScriptObject( struct IScriptObject * val)
{
	this->m_type = valueScriptObject;

	this->m_count = 0;

	this->m_psoValue = val;

	XASSERT(!m_fNeedsFreeValuePointer);

}

void CValue::SetXMLObject( CXMLObject * val )
{
	this->m_type = valueXMLObject;

	this->m_count = 0;

	this->m_pxoValue = val;

	XASSERT(!m_fNeedsFreeValuePointer);
}

void CValue::SetThickness( struct XRECTF_RB * val )
{
	this->m_type = valueThickness;
	this->m_count = sizeof(XRECTF_RB) /sizeof(XFLOAT);
	this->m_pvValue = val;
	XASSERT(!m_fNeedsFreeValuePointer);
}

void CValue::SetCornerRadius( struct XRECTF_CR * val )
{
	this->m_type = valueCornerRadius;
	this->m_count = sizeof(XRECTF_CR) /sizeof(XFLOAT);
	this->m_pvValue = val;
	XASSERT(!m_fNeedsFreeValuePointer);
}

void CValue::SetInternalHandler( PFHandler val )
{
	this->m_type = valueInternalHandler;
	this->m_count = 0;
	this->m_pHandler = val;
	XASSERT(!m_fNeedsFreeValuePointer);
}

void CValue::SetSize( struct XSIZEF * val )
{
	this->m_type = valueSize;
	this->m_count = sizeof(XSIZEF) /sizeof(XFLOAT);
	this->m_pvValue = val;
	XASSERT(!m_fNeedsFreeValuePointer);
}

void CValue::SetGridLength( struct XGRIDLENGTH * val )
{
	this->m_type = valueSize;
	this->m_count = 2;
	this->m_pvValue = val;
	XASSERT(!m_fNeedsFreeValuePointer);
}

void CValue::SetIObject( struct IObject * val)
{
	this->m_type = valueIObject;
	this->m_count = 0;
	this->m_pioValue = val;
	XASSERT(!m_fNeedsFreeValuePointer);
}

void CValue::SetNull()
{
	this->m_type = valueNull;
	this->m_count = 0;
	this->m_pvValue = NULL;
	XASSERT(!m_fNeedsFreeValuePointer);
}

void CValue::SetIntPtr( void * val )
{
	this->m_type = valueIntPtr;
	this->m_count = 0;
	this->m_pvValue = val;
	XASSERT(!m_fNeedsFreeValuePointer);
}

void CValue::SetIUnknown( void * val )
{
	this->m_type = valueIUnknown;
	this->m_count = 0;
	this->m_pvValue = val;
	XASSERT(!m_fNeedsFreeValuePointer);
}

void CValue::DebugNullCharCheck()
{
	for(XUINT32 i = 0;i<this->m_count;i++)
	{
		XASSERT(m_pchValue[i]);
	}
}

void CValue::SetString( XUINT32 cchString, XCHAR * psz )
{
	XASSERT(!m_fNeedsFreeValuePointer);

	this->m_type = valueString;
	this->m_count = cchString <= 0xFFFFFF ? cchString : 0xFFFFFF;
	this->m_pchValue = this->m_count != 0 ? psz : NULL;
	this->DebugNullCharCheck();
}

//void CValue::SetString( struct XSTRING * val )
//{
//
//	throw std::logic_error("The method or operation is not implemented.");
//}

void CValue::SetString( CXString * val )
{
	XASSERT(!m_fNeedsFreeValuePointer);

	this->m_type = valueString;

	if ( val )
	{
		this->m_count = val->GetCount() <= 0xFFFFFF ? val->GetCount() : 0xFFFFFF;
		this->m_pchValue = this->m_count != 0 ? val->GetBuffer() : NULL;
	}
	else
	{
		this->m_count = 0;
		this->m_pchValue = NULL;
	}
}

void CValue::SetFloatArray( XUINT32 cnt, XFLOAT * pe )
{
	XASSERT(!m_fNeedsFreeValuePointer);


	this->m_type = valueFloatArray;

	this->m_count = cnt <= 0xFFFFFF ? cnt : 0xFFFFFF;

	this->m_peValue = this->m_count != 0 ? pe : NULL;

}

void CValue::SetPointArray( XUINT32 cnt, XFLOAT * pe )
{
	XASSERT(!m_fNeedsFreeValuePointer);

	this->m_type = valuePointArray;

	this->m_count = cnt <= 0xFFFFFF ? cnt : 0xFFFFFF;

	this->m_peValue = this->m_count !=0 ? pe : NULL;
}

void * CValue::GetValuePointer()
{
	void *result;

	switch ( this->m_type )
	{
	case valueFloat:
		result = &this->m_eValue;
		break;
	case valueSigned:
		result = &this->m_iValue;
		break;
	case valueBool:
	case valueEnum:
	case valueColor:
		result = &this->m_nValue;
		break;
	case valueAny:
	case valueNull:
		result = NULL;
		break;
	case valueString:
	case valuePoint:
	case valueRect:
	case valueFloatArray:
	case valueByteArray:
	case valueObject:
	case valueScriptObject:
	case valueXMLObject:
	case valueThickness:
	case valueInternalHandler:
	case valueSize:
	case valueGridLength:
	case valuePointArray:
	case valueCornerRadius:
	case valueIntPtr:
	case valueIObject:
	case valueDouble:
	case valueDPoint:
	case valueIUnknown:
		result = this->m_pvValue;
		break;
	default:
		result = NULL;
		break;
	}
	return result;
}

void CValue::FreeValuePointer()
{

	this->m_fNeedsFreeValuePointer = FALSE;


	switch (this->m_type )
	{
	case valueAny:
	case valueFloat:
	case valueSigned:
	case valueBool:
	case valueEnum:
	case valueColor:
	case valueNull:
		return;
	case valueString:
		delete[] this->m_pchValue;
		this->m_pchValue = NULL;
		this->m_count = 0;
		break;
	case valuePoint:
	case valueRect:
	case valueThickness:
	case valueSize:
	case valueGridLength:
	case valueCornerRadius:
		delete (void*)this->m_pvValue;
		this->SetNull();
		break;
	case valueDouble:
		delete (void *)this->m_pdfValue;
		this->SetNull();
		break;
	case valueDPoint:
		delete (void*)this->m_pvValue;
		this->SetNull();
		break;
	case valueFloatArray:
		delete[] this->m_peValue;
		this->SetNull();
		break;
	case valueObject:
		if (this->m_pdoValue )
		{
			this->m_pdoValue->Release();
			this->m_psoValue = NULL;
		}
		break;
	case valueScriptObject:
		if(this->m_psoValue)
		{
			this->m_psoValue->Release();
			this->m_psoValue = NULL;
		}
		break;
	case valueIObject:
		if(this->m_pioValue)
		{
			this->m_pioValue->Release();
			this->m_pioValue = NULL;
		}
		break;
	default:

		TRACE_ENSURE1(FALSE,L" FreeValuePointer is not implemented for this type.");

		break;
	}
}

void CValue::SetReleaseValuePointer( XBOOL inShouldReleaseValuePointer )
{
	this->m_fNeedsFreeValuePointer = inShouldReleaseValuePointer;
}

XBOOL CValue::GetReleaseValuePointer()
{
	return this->m_fNeedsFreeValuePointer;
}

void CValue::SetIsIndependent( XBOOL isIndependent )
{
	this->m_isIndependent = isIndependent;
}

XBOOL CValue::IsIndependent()
{
	return this->m_isIndependent;
}

HRESULT ConvertForManaged(CValue *pData, CValue value, XINT32 *pTypeIndex, XBOOL bReleaseInterfaceForBoxes)
{
	throw std::logic_error("The method or operation is not implemented.");

}

HRESULT CValue::CopyFrom( CValue source )
{
	HRESULT hr = S_OK;
	if ( source.m_type == valueObject )
	{
		if(this->m_pdoValue)
		{
			this->m_pdoValue->AddRef();
		}
	}

	XASSERT_SUCCESSED(ConvertForManaged(this, source, 0, TRUE));

	return hr;
}

XFLOAT CValue::AsFloat()
{
	if ( this->m_type == valueFloat )
		return this->m_eValue;
	else
		return 0.0;
}

HRESULT CValue::GetFloat( XFLOAT & val )
{
	val = this->AsFloat();
	return this->m_type != valueFloat ? E_UNEXPECTED : S_OK;
}

XDOUBLE CValue::AsDouble()
{
	if ( this->m_type == valueDouble )
		return *this->m_pdfValue;
	else
		return 0.0;
}

HRESULT CValue::GetDouble( XDOUBLE & value )
{
	value = *this->m_pdfValue;
	return this->m_type != valueDouble ? E_UNEXPECTED : S_OK;
}

XINT32 CValue::AsSigned()
{
	if ( this->m_type == valueSigned )
		return this->m_iValue;
	else
		return 0;
}

HRESULT CValue::GetSigned( XINT32 & val )
{
	val = this->m_iValue;
	return this->m_type != valueSigned ? E_UNEXPECTED : S_OK;
}

XBOOL CValue::AsBool()
{
	if ( this->m_type == valueBool )
		return this->m_nValue != 0;
	else
		return FALSE;
}

HRESULT CValue::GetBool( XBOOL & value )
{
	value = this->m_nValue!=0;
	return this->m_type != valueBool ? E_UNEXPECTED : S_OK;
}

XUINT32 CValue::AsEnum()
{
	if ( this->m_type == valueEnum )
		return this->m_nValue;
	else
		return NULL;
}

HRESULT CValue::GetEnum( XUINT32 & value )
{
	value = this->m_nValue;
	return this->m_type != valueEnum ? E_UNEXPECTED : S_OK;
}

XUINT32 CValue::AsColor()
{
	if ( this->m_type == valueColor )
		return this->m_nValue;
	else
		return NULL;
}

HRESULT CValue::GetColor( XUINT32 & value )
{
	value = this->m_nValue;
	return this->m_type!=valueColor ? E_UNEXPECTED : S_OK;
}

CXString CValue::AsString() const
{
	CXString * result = NULL;
	if ( this->m_type == valueString && this->m_pchValue )
	{
		result = new CXString(this->m_count, this->m_pchValue);
	}
	else
	{
		result = new CXString(0, NULL);
	}


	return *result;
}

HRESULT CValue::GetString( CXString & val )
{

	CXString result(this->AsString());

	val.cString = result.cString;
	val.pString = result.pString;
	val.flags = result.flags;


	return this->m_type != valueString ? E_UNEXPECTED : S_OK;
}

struct XPOINTF * CValue::AsPoint()
{
	if ( this->m_type == valuePoint )
		return (XPOINTF *)this->m_pvValue;
	else
		return NULL;
}


HRESULT CValue::GetPoint( struct XPOINTF  & val )
{
	val = *((XPOINTF *)this->m_pvValue);
	
	return this->m_type != valuePoint ? E_UNEXPECTED : S_OK;
}

struct XPOINTD * CValue::AsDPoint()
{
	if ( this->m_type == valueDPoint )
		return (XPOINTD *)this->m_pvValue;
	else
		return NULL;
}

HRESULT CValue::GetDPoint( struct XPOINTD  & val )
{
	val = *((XPOINTD *)this->m_pvValue);

	return this->m_type != valueDPoint ? E_UNEXPECTED : S_OK;
}

struct XRECTF_WH * CValue::AsRect()
{
	if ( this->m_type == valueRect )
		return (XRECTF_WH *)this->m_pvValue;
	else
		return NULL;
}

HRESULT CValue::GetRect( struct XRECTF_WH  & val )
{
	val = *((XRECTF_WH *)this->m_pvValue);

	return this->m_type != valueRect ? E_UNEXPECTED : S_OK;
}

CDependencyObject * CValue::AsObject()
{
	if ( this->m_type == valueObject )
		return this->m_pdoValue;
	else
		return NULL;
}

HRESULT CValue::GetObject( CDependencyObject  & val )
{
	val = *(this->m_pdoValue);

	return this->m_type != valueObject ? E_UNEXPECTED : S_OK;
}

struct IScriptObject * CValue::AsScriptObject()
{
	if ( this->m_type == valueScriptObject )
		return this->m_psoValue;
	else
		return NULL;
}

HRESULT CValue::GetScriptObject( struct IScriptObject  & val )
{
	val = *(this->m_psoValue);

	return this->m_type != valueScriptObject ? E_UNEXPECTED : S_OK;
}

CXMLObject * CValue::AsXMLObject()
{
	if ( this->m_type == valueXMLObject )
		return this->m_pxoValue;
	else
		return NULL;
}

HRESULT CValue::GetXMLObject(CXMLObject & val )
{
	val = *(this->m_pxoValue);

	return this->m_type != valueXMLObject ? E_UNEXPECTED : S_OK;
}

struct IObject * CValue::AsIObject()
{
	if ( this->m_type == valueIObject )
		return this->m_pioValue;
	else
		return NULL;
}

HRESULT CValue::GetIObject( struct IObject  & val )
{
	val = *(this->m_pioValue);

	return this->m_type != valueIObject ? E_UNEXPECTED : S_OK;
}

struct XRECTF_RB * CValue::AsThickness()
{
	if ( this->m_type == valueThickness )
		return (XRECTF_RB *)this->m_pvValue;
	else
		return NULL;
}

HRESULT CValue::GetThickness( struct XRECTF_RB  & val )
{
	val = *((XRECTF_RB *)this->m_pvValue);

	return this->m_type != valueThickness ? E_UNEXPECTED : S_OK;
}

PFHandler CValue::AsInternalHandler()
{
	if ( this->m_type == valueInternalHandler )
		return (PFHandler )this->m_pvValue;
	else
		return NULL;
}

HRESULT CValue::GetInternalHandler( PFHandler  & val )
{
	val = (PFHandler )this->m_pvValue;

	return this->m_type != valueInternalHandler ? E_UNEXPECTED : S_OK;
}

struct XSIZEF * CValue::AsSize()
{
	if ( this->m_type == valueSize )
		return (XSIZEF *)this->m_pvValue;
	else
		return NULL;
}

HRESULT CValue::GetSize( struct XSIZEF  & val )
{
	val = *((XSIZEF *)this->m_pvValue);

	return this->m_type != valueSize ? E_UNEXPECTED : S_OK;
}

struct XGRIDLENGTH * CValue::AsGridLength()
{
	if ( this->m_type == valueGridLength )
		return (XGRIDLENGTH *)this->m_pvValue;
	else
		return NULL;
}

HRESULT CValue::GetGridLength( struct XGRIDLENGTH  & val )
{
	val = *((XGRIDLENGTH *)this->m_pvValue);

	return this->m_type != valueGridLength ? E_UNEXPECTED : S_OK;
}

struct XRECTF_CR * CValue::AsCornerRadius()
{
	if ( this->m_type == valueCornerRadius )
		return (XRECTF_CR *)this->m_pvValue;
	else
		return NULL;
}

HRESULT CValue::GetCornerRadius( struct XRECTF_CR  & val )
{
	val = *((XRECTF_CR *)this->m_pvValue);

	return this->m_type != valueCornerRadius ? E_UNEXPECTED : S_OK;
}

XBOOL CValue::IsNull()
{
	return this->m_type == valueNull
		|| this->m_type == valueObject && !this->m_pdoValue
		|| this->m_type == valueScriptObject && !this->m_psoValue
		|| this->m_type == valueString && !this->m_pchValue
		|| this->m_type == valueScriptObject && !this->m_psoValue
		|| this->m_type == valueIObject && !this->m_pioValue
		|| this->m_type == valueInternalHandler && !this->m_pHandler
		|| this->m_type == valueIUnknown && !this->m_pvValue;
}

enum ValueType CValue::GetType()
{
	return this->m_type;
}
